import csv
import datetime
import os
import sys
import time

from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta

class Entity(object):

    @classmethod
    def get_db_key(cls):
        return cls.__module__.split('.')[2]

    @property
    def db_key(self):
        return self.get_db_key()

    def get_column_default(self, key):
        """Get default set in SQLA table (NOT server default)."""
        # XXX: Is this method really necessary?
        default = self.__table__.columns.get(key).default
        if not default:
            return None
        return default.arg

    def _fixup(self): 
        '''(over-ride me): _fixup is called after creating an object via dictionary '''

    @classmethod
    def set_schema(cls, schema):
        cls.__table__.schema = schema

    @classmethod
    def get_filename(cls, ext='txt'):
        return '%s.%s' % (cls.__tablename__, ext)

    @classmethod
    def get_filepath(cls, directory='.', default='no file found'):
        ret_val = default 
        for x in ('txt', 'csv', 'doc'):
            file = cls.get_filename(x)
            file_path = os.path.join(directory, file)
            if os.path.exists(file_path):
                ret_val = file_path
                break

        return ret_val

    @classmethod
    def make_record(cls, row):
        # clean dict
        for k, v in row.items():
            if isinstance(v, basestring):
                v = v.strip()
            if (k not in cls.__table__.c):
                del row[k]
            elif not v:
                row[k] = None
            elif k.endswith('date'):
                row[k] = datetime.datetime.strptime(v, '%Y%m%d').date()

        return row

    @classmethod
    def from_dict(cls, attrs):
        clean_dict = cls.make_record(attrs)
        c = cls(**clean_dict)
        c._fixup()
        return c

    def to_dict(self):
        ''' convert a SA object into a dict that is serializable to JSON
        ''' 
        ret_val = self.__dict__

        ''' not crazy about this hack, but ... 
            the __dict__ on a SqlAlchemy object contains hidden crap that we delete from the class dict
        '''
        if set(['_sa_instance_state']).issubset(ret_val):
            del ret_val['_sa_instance_state']

        ''' we're using 'created' as the date parameter, so cnvert values to strings
            TODO: better would be to detect date & datetime objects, and convert those...
        '''
        if set(['created']).issubset(ret_val):
            ret_val['created'] = ret_val['created'].__str__();

        return ret_val 


    @classmethod
    def row2dict(cls, row):
        d = {}
        for columnName in row.__table__.columns.keys():
            d[columnName] = getattr(row, columnName)

        return d

    @classmethod
    def q2dict(cls, q):
        for r in q.first():
            print cls.row2dict(r)


    @classmethod
    def load(cls, engine, directory='.', file=None):
        records = []
        if(file is None):
            file_path = cls.get_filepath(directory)
        else:
            file_path = os.path.join(directory, file)

        if os.path.exists(file_path) == False:
            print "Could not find file", file_path
        else:
            print "Loading file", file_path
            file = open(file_path, 'r')
            reader = csv.DictReader(file)
            table = cls.__table__
            engine.execute(table.delete())
            Session = sessionmaker(bind=engine)
            session = Session()
            i = 0
            for row in reader:
                records.append(cls.from_dict(row))
                i += 1
                # commit every 10,000 records to the database to manage memory usage
                if i >= 10000:
                    session.add_all(records)
                    session.flush()
                    session.commit()

                    records = []
                    i = 0
            if len(records) > 0:
                session.add_all(records)
                session.flush()
                session.commit()
                session.flush()
                session.close()

            file.close()

class EntityMeta(DeclarativeMeta):
    """Place holder."""

Base = declarative_base(cls=Entity)
""":class:`Base` will be a subclass of :class:`Entity`."""

